package com.linln.admin.pcs.api;

import com.linln.admin.pcs.service.WechatPayRefundService;
import com.linln.admin.pcs.service.WxJsPayService;
import com.linln.admin.util.WXPayUtil;
import com.linln.common.data.QuerySpec;
import com.linln.common.utils.ResultVoUtil;
import com.linln.common.utils.SnowflakeIdGenerator;
import com.linln.common.vo.ResultVo;
import com.linln.modules.system.domain.*;
import com.linln.modules.system.repository.*;
import com.linln.modules.system.service.OrderAmountsService;
import com.linln.modules.system.util.WeChatPayUtil;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/js/wechat/")
public class WxJsPayController {

    private final static Logger logger = LoggerFactory.getLogger(WxJsPayController.class);

    @Value("${wx.appId}")
    private String APPID;

    @Value("${wx.notifyUrl}")
    private  String NOTIFY_URL;


    @Autowired
    private WxJsPayService wxJsPayService;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private CompanyRepository companyRepository;

    @Autowired
    private CompanyParamRepository companyParamRepository;

    @Autowired
    private OrderAmountsService orderAmountsService;

    @Autowired
    private WechatPayRefundService wechatPayRefundService;

    @Autowired
    private PayRecordRepository payRecordRepository;

    @Autowired
    private OrderPayRepository orderPayRepository;

    /**
     * 临时预缴费用接口
     * @return
     */
    @PostMapping("temp/pay/fee")
    @Transactional(rollbackFor = Exception.class)
    public ResultVo weixinH5Pays(@RequestBody PayParam payParam){
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("sn", QuerySpec.EQUAL, payParam.getOutTradeNo());
        List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
        Map<String, String> payParams = new HashMap<>();
        if (orderList.size()>0){
            Order order = orderList.get(0);
            //1 陪护 2 陪诊 3 陪检
            int type = order.getType();
            String msg = "";
            switch (type){
                case 1:msg = "陪护";break;
                case 2:msg = "陪诊";break;
                case 3:msg = "陪检";break;
            }
            //判断是陪护还是陪诊陪检  如果是陪护则预缴费用
            if (type == 1) {
                //修改订单状态
                order.setOrderStatus(4);
                //新增金额变动表
                orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单预缴费用",2);
            } else {
                //新增金额变动表
                orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单缴费",2);
            }
            order.setBalance(Double.valueOf(payParam.getTotalFee()));
            //支付成功
            order.setPayStatus((byte) 1);
            orderRepository.save(order);


            payParams.put("appId", "");
            payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            payParams.put("nonceStr", generateNonceStr());
            payParams.put("package", "prepay_id=1");
            payParams.put("signType", "MD5");

            // 生成签名
            String paySign = "dssafdsafdsafds55555";
            payParams.put("paySign", paySign);

            //更新支付状态
            order.setBalance(Double.valueOf(payParam.getTotalFee()));
            order.setPayStatus((byte) 2);
            orderRepository.save(order);

            // 返回前端参数
            Map<String, Object> result = new HashMap<>();
            result.put("payParams", payParams);
            return ResultVoUtil.success(payParams);
        }
        return ResultVoUtil.success("支付成功");
    }



    /**
     * 支付接口
     * @param payParam
     * @return
     * @throws Exception
     */
    @PostMapping("pay")
    @Transactional(rollbackFor = Exception.class)
    public ResultVo pay(@RequestBody PayParam payParam) throws Exception {
        logger.error("支付:"+payParam.getOutTradeNo());
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("sn", QuerySpec.EQUAL, payParam.getOutTradeNo());
        List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
        if (orderList.size()>0){
            Order order = orderList.get(0);
            String totalFee1 = payParam.getTotalFee();
            double tf = Double.parseDouble(totalFee1);
            Double price = order.getPrice();
            int type1 = order.getType();
            int stageType = 0;
            int hourNum = 0;
            if (type1==1){
                stageType = order.getStageType();
                if (stageType==2){
                    hourNum = order.getHourNum();
                    BigDecimal dprices = new BigDecimal(price);
                    BigDecimal hns = new BigDecimal(hourNum);
                    BigDecimal muls = dprices.multiply(hns);
                    BigDecimal temps = muls.setScale(2, RoundingMode.HALF_UP);
                    price = temps.doubleValue();
                }
            }
            //判断支付金额大于需要的金额
            if (tf>=price){
                Long companyId = order.getCompanyId();
                QuerySpec querySpec1 = QuerySpec.matching();
                querySpec1.withMatcherValue("companyId", QuerySpec.EQUAL, String.valueOf(companyId));
                List<CompanyParam> companyParamList = companyParamRepository.findAll(QuerySpec.of(querySpec1));
                if (companyParamList.size()>0){
                    CompanyParam companyParam = companyParamList.get(0);
                    if (ObjectUtils.isNotEmpty(companyParam.getApiKey())&&ObjectUtils.isNotEmpty(companyParam.getKeyPath())
                            &&ObjectUtils.isNotEmpty(companyParam.getMchId())){
                        payParam.setApiKey(companyParam.getApiKey());
                        payParam.setKeyPath(companyParam.getKeyPath());
                        payParam.setMchId(companyParam.getMchId());
                        payParam.setAppId(APPID);
                        payParam.setNotifyUrl(NOTIFY_URL);
                        payParam.setCompanyId(String.valueOf(companyId));
                        payParam.setPatientName(order.getPatientName());


                        //重新生成子订单号 所有的支付不用原来的订单号
                        //生成订单号
                        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
                        long l = idGenerator.nextId();
                        String orderChildNo = "NO"+l;
                        payParam.setOrderChildNo(orderChildNo);

                        // 生成预支付订单
                        Map<String, Object> results = wxJsPayService.createOrder(payParam);
                        String code = (String) results.get("code");
                        if (code.equals("1")){
                            Map<String, String> orderResult = (Map<String, String>) results.get("data");
                            logger.error("支付接口:"+payParam.getOrderChildNo()+" 返回结果:"+orderResult);
                            // 生成前端调用参数
                            Map<String, String> payParams = new HashMap<>();
                            payParams.put("appId", orderResult.get("appid"));
                            payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                            payParams.put("nonceStr", generateNonceStr());
                            payParams.put("package", "prepay_id=" + orderResult.get("prepay_id"));
                            payParams.put("signType", "MD5");

                            // 生成签名
                            String paySign = WXPayUtil.generateSign(payParams, payParam.getApiKey());
                            payParams.put("paySign", paySign);

                            payParams.put("orderChildNo", orderChildNo);
                            int type = order.getType();

                            //转换需要支付的金额
                            BigDecimal tpa = new BigDecimal(tf);
                            BigDecimal bnum = new BigDecimal(100);
                            BigDecimal result = tpa.divide(bnum, 2, RoundingMode.HALF_UP);

                            if (type==1){
                                Double balance = order.getBalance();
                                int num = order.getNum();
                                //判断陪护订单之前是否已经预缴过费用  如果有 则增加费用
                                if (num>0){
                                    BigDecimal b = new BigDecimal(balance);

                                    order.setBalance(b.add(result).setScale(2, RoundingMode.HALF_UP).doubleValue());
                                    //记录本次缴费
                                    order.setCurrentMoney(result.doubleValue());
                                }else{
                                    double temp = result.doubleValue();
                                    order.setBalance(temp);
                                    //记录本次缴费
                                    order.setCurrentMoney(temp);
                                    //更新支付状态
                                    order.setBeforeStatus((byte) 2);
                                }
                            }else{
                                //更新支付状态
                                double temp = result.doubleValue();
                                order.setBalance(temp);
                                order.setPayStatus((byte) 2);
                                //记录本次缴费
                                order.setCurrentMoney(temp);
                            }
                            orderRepository.save(order);

                            //生成子订单表
                            OrderPay orderPay = new OrderPay();
                            orderPay.setOrderNo(payParam.getOutTradeNo());
                            orderPay.setOrderChildNo(payParam.getOrderChildNo());
                            orderPay.setPatientId(order.getPatientId());
                            orderPay.setPrice(result.doubleValue());
                            orderPay.setType(type1);
                            orderPay.setStatus((byte) 1);
                            orderPayRepository.save(orderPay);

                            // 返回前端参数
                            logger.error("返回前端:"+payParams);
                            return ResultVoUtil.success(payParams);
                        }else{
                            return ResultVoUtil.error((String) results.get("msg"));
                        }
                    }
                }
            }else{
                return ResultVoUtil.error("支付金额错误");
            }
        }
        return ResultVoUtil.error("未找到公司");
    }

    /**
     * 查询订单支付状态
     * @param sn
     * @return
     * @throws Exception
     */
    @GetMapping("check/order")
    public ResultVo checkOrder(@RequestParam("sn") String sn,@RequestParam("orderChildNo") String orderChildNo) throws Exception {
        logger.error("查询订单支付状态:"+sn);
        PayParam payParam = new PayParam();
        payParam.setOutTradeNo(orderChildNo);
        payParam.setAppId(APPID);
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("sn", QuerySpec.EQUAL, sn);
        List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
        if (orderList.size()>0){
            Order order = orderList.get(0);
            Long companyId = order.getCompanyId();
            QuerySpec querySpec1 = QuerySpec.matching();
            querySpec1.withMatcherValue("companyId", QuerySpec.EQUAL, String.valueOf(companyId));
            List<CompanyParam> companyParamList = companyParamRepository.findAll(QuerySpec.of(querySpec1));
            if (companyParamList.size()>0){
                CompanyParam companyParam = companyParamList.get(0);
                if (ObjectUtils.isNotEmpty(companyParam.getApiKey())&&ObjectUtils.isNotEmpty(companyParam.getKeyPath())
                        &&ObjectUtils.isNotEmpty(companyParam.getMchId())){
                    payParam.setApiKey(companyParam.getApiKey());
                    payParam.setKeyPath(companyParam.getKeyPath());
                    payParam.setMchId(companyParam.getMchId());
                    Map<String, String> map = wxJsPayService.queryOrder(payParam);
                    logger.error("订单返回:"+map);
                    String code = map.get("code");
                    String msg = map.get("msg");
                    if (code.equals("200")){
                        //支付成功
                        changeOrderStatus(order,orderChildNo,"1",msg);
                        return ResultVoUtil.success(map.get("msg"));
                    } else if (code.equals("400")) {
                        return ResultVoUtil.error(400,map.get("msg"));
                    } else{
                        changeOrderStatus(order,orderChildNo,"2",msg);
                        return ResultVoUtil.error(map.get("msg"));
                    }
                }else{
                    return ResultVoUtil.error(100,"支付参数错误");
                }
            }else{
                return ResultVoUtil.error(100,"未找到公司");
            }
        }else{
            return ResultVoUtil.error(100,"未找到订单");
        }
    }


    /**
     * 微信支付回调 (不做实际操作)
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("pay/notify")
    public String handleNotify(HttpServletRequest request) throws Exception {
        try {
           /* // 读取微信回调数据
            BufferedReader reader = request.getReader();
            StringBuilder xmlData = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                xmlData.append(line);
            }

            // 将 XML 数据转换为 Map
            Map<String, String> notifyData = xmlToMap(xmlData.toString());
            logger.error("微信支付回调参数："+notifyData);
            // 验证签名
            if (!verifySignature(notifyData)) {
                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[Signature verification failed]]></return_msg></xml>";
            }

            // 处理回调逻辑
            processNotifyData(notifyData);*/

            // 返回成功响应给微信服务器
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
        } catch (Exception e) {
            e.printStackTrace();
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[Server error]]></return_msg></xml>";
        }
    }

    /**
     * 退款回调 (不做实际操作)
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("refund/callback")
    public String refundCallback(HttpServletRequest request) throws Exception {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
        // 1. 读取请求体XML数据
        /*String xmlData = request.getReader().lines().collect(Collectors.joining());

        // 2. 解析XML为Map
        Map<String, String> responseMap = xmlToMap(xmlData);
        logger.error("退款回调MAP:"+responseMap);
        String out_trade_no = responseMap.get("out_trade_no");
        logger.error("退款回调订单号:"+out_trade_no);
        //根据订单号查公司
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("sn", QuerySpec.EQUAL, out_trade_no);
        List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
        if (orderList.size()>0){
            Order order = orderList.get(0);
            QuerySpec querySpec1 = QuerySpec.matching();
            querySpec1.withMatcherValue("companyId", QuerySpec.EQUAL, String.valueOf(order.getCompanyId()));
            querySpec1.withMatcherValue("status", QuerySpec.EQUAL, "1");
            List<CompanyParam> companyParamList = companyParamRepository.findAll(QuerySpec.of(querySpec1));
            if (companyParamList.size()>0){
                CompanyParam companyParam = companyParamList.get(0);
                logger.error("退款回调companyParam:"+companyParam);
                // 3. 验证签名
                if (!verifySign(responseMap, companyParam.getApiKey())) {
                    return generateErrorXml("签名验证失败");
                }
                logger.error("签名验证成功");
                // 4. 处理业务逻辑
                String returnCode = responseMap.get("return_code");
                String resultCode = responseMap.get("result_code");

                if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                    logger.error("退款成功逻辑");
                    // 退款成功逻辑
                    String outRefundNo = responseMap.get("out_refund_no");
                    String refundId = responseMap.get("refund_id");
                    int refundFee = Integer.parseInt(responseMap.get("refund_fee"));
                    order.setRefundStatus((byte) 2);
                    orderRepository.save(order);
                    return generateSuccessXml();
                } else {
                    // 退款失败逻辑
                    String errorMsg = responseMap.get("return_msg");
                    order.setRefundStatus((byte) 3);
                    order.setRefundRemark(errorMsg);
                    orderRepository.save(order);
                    return generateErrorXml(errorMsg);
                }
            }
        }
        return generateErrorXml("签名验证失败");*/
    }

    /**
     * 支付成功或失败后更新订单信息
     */
    private void changeOrderStatus(Order order,String orderChildNo,String status,String msgs) {
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("orderChildNo", QuerySpec.EQUAL, orderChildNo)
                .withMatcherValue("operatorStatus", QuerySpec.EQUAL, "1")
                .withMatcherValue("payStatus", QuerySpec.EQUAL, "1")
                .withMatcherValue("payBackStatus", QuerySpec.EQUAL, "2");
        List<PayRecord> recordList = payRecordRepository.findAll(QuerySpec.of(querySpec));
        if (status.equals("1")){
            //1 陪护 2 陪诊 3 陪检
            int type = order.getType();
            String msg = "";
            switch (type){
                case 1:msg = "陪护";break;
                case 2:msg = "陪诊";break;
                case 3:msg = "陪检";break;
            }
            //判断是陪护还是陪诊陪检  如果是陪护则预缴费用
            if (type == 1) {
                int num = order.getNum();
                //判断陪护订单之前是否已经预缴过费用  如果没有 则是第一次充值 则修改订单状态
                if (num==0){
                    //修改预交费状态
                    order.setBeforeStatus((byte) 1);
                    //修改订单状态
                    order.setOrderStatus(4);
                    //支付成功
                    order.setPayStatus((byte) 1);
                    orderRepository.save(order);
                }
                //新增金额变动表
                orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单预缴费用",2);
            } else {
                //新增金额变动表
                orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单缴费",2);
                //支付成功
                order.setPayStatus((byte) 1);
                orderRepository.save(order);
            }

            if (recordList.size()>0){
                PayRecord payRecord = recordList.get(0);
                payRecord.setPayBackStatus(1);
                payRecordRepository.save(payRecord);
            }

        }else{
            //1 陪护 2 陪诊 3 陪检
            int type = order.getType();
            //判断是陪护还是陪诊陪检  如果是陪护则预缴费用
            if (type == 1) {
                int num = order.getNum();
                if (num==0){
                    order.setBeforeStatus((byte) 3);
                }
                //预交费失败
                order.setBeforeRemark(msgs);
            }else{
                order.setPayStatus((byte) 3);
                //支付失败
                order.setPayRemark(msgs);
            }
            orderRepository.save(order);
            if (recordList.size()>0){
                PayRecord payRecord = recordList.get(0);
                payRecord.setPayBackStatus(0);
                if (StringUtils.isNotEmpty(order.getPayRemark())){
                    payRecord.setPayRemark(order.getPayRemark());
                }
                payRecordRepository.save(payRecord);
            }
        }
    }




    private boolean verifySign(Map<String, String> params, String apiKey) throws Exception {
        if (!params.containsKey("sign")) return false;
        String receivedSign = params.get("sign");

        // 复制一份新Map避免修改原始数据
        Map<String, String> verifyMap = new HashMap<>(params);
        verifyMap.remove("sign");

        String generatedSign = WXPayUtil.generateSign(verifyMap, apiKey);
        return generatedSign.equalsIgnoreCase(receivedSign);
    }

    // XML 响应工具方法
    private String generateSuccessXml() {
        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    private String generateErrorXml(String errorMsg) {
        return String.format("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml>", errorMsg);
    }



    private Map<String, String> xmlToMap(String xml) {
        XStream xStream = new XStream();
        xStream.alias("xml", Map.class);
        return (Map<String, String>) xStream.fromXML(xml);
    }

    private boolean verifySignature(Map<String, String> data) throws Exception {
        String outTradeNo = data.get("out_trade_no");
        if (null == outTradeNo || outTradeNo.isEmpty()) {
            return false;
        }
        QuerySpec querySpec = QuerySpec.matching();
        querySpec.withMatcherValue("sn", QuerySpec.EQUAL, outTradeNo);
        List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
        if (orderList.size()>0){
            Order order = orderList.get(0);
            Long companyId = order.getCompanyId();
            QuerySpec querySpec1 = QuerySpec.matching();
            querySpec1.withMatcherValue("companyId", QuerySpec.EQUAL, String.valueOf(companyId));
            List<CompanyParam> companyParamList = companyParamRepository.findAll(QuerySpec.of(querySpec1));
            if (companyParamList.size()>0){
                CompanyParam companyParam = companyParamList.get(0);
                String apiKey = companyParam.getApiKey(); // 商户 API 密钥 通过订单查询对应公司商户信息
                String sign = WeChatPayUtil.generateSign(data, apiKey);
                return sign.equals(data.get("sign"));
            }
        }
        return false;
    }

    private void processNotifyData(Map<String, String> data) {
        // 根据业务需求处理回调数据
        String outTradeNo = data.get("out_trade_no"); // 商户订单号
        String transactionId = data.get("transaction_id"); // 微信支付订单号
        String totalFee = data.get("total_fee"); // 订单金额
        String resultCode = data.get("result_code"); // 业务结果

        if ("SUCCESS".equals(resultCode)) {
            // 更新订单状态为“已支付”
            updateOrderStatus(data, "1");
        }else{
            // 更新订单状态为“支付失败”
            updateOrderStatus(data, "2");
        }
    }

    private void updateOrderStatus(Map<String, String> data, String status) {
        logger.error("更新订单状态："+status);
        String outTradeNo = data.get("out_trade_no");
        String totalFee = data.get("total_fee"); // 订单金额
        if (status.equals("1")){
            QuerySpec querySpec = QuerySpec.matching();
            querySpec.withMatcherValue("sn", QuerySpec.EQUAL, outTradeNo);
            List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
            logger.error("查询订单:"+outTradeNo);
            if (orderList.size()>0) {
                Order order = orderList.get(0);
                //1 陪护 2 陪诊 3 陪检
                int type = order.getType();
                String msg = "";
                switch (type){
                    case 1:msg = "陪护";break;
                    case 2:msg = "陪诊";break;
                    case 3:msg = "陪检";break;
                }
                //判断是陪护还是陪诊陪检  如果是陪护则预缴费用
                if (type == 1) {
                    //修改订单状态
                    order.setOrderStatus(4);
                    //新增金额变动表
                    orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单预缴费用",2);
                } else {
                    //新增金额变动表
                    orderAmountsService.updateOrderAmounts(order,"患者"+msg+"订单缴费",2);
                }
                order.setBalance(Double.valueOf(totalFee));
                //支付成功
                order.setPayStatus((byte) 1);
                orderRepository.save(order);
            }
        }else {
            QuerySpec querySpec = QuerySpec.matching();
            querySpec.withMatcherValue("sn", QuerySpec.EQUAL, outTradeNo);
            List<Order> orderList = orderRepository.findAll(QuerySpec.of(querySpec));
            if (orderList.size()>0){
                Order order = orderList.get(0);
                order.setPayStatus((byte) 3);
                order.setPayRemark(String.valueOf(data));
                orderRepository.save(order);
            }
        }

    }

    private String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }
}
